﻿// ----------------------------------------------------------------------
// <author name="Moses Kehengu"/>
// <copyright file="ReportProcessor.cs" company="Futures Group International">
//     Copyright statement. All right reserved
// </copyright>
//
// ------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using DataModels.Common;
using DataModels.Enumerations;
using DataModels;
using GenericTools.OptionBPlus;
using GenericTools.Models;

namespace GenericTools.ReportProcessing
{
    #region Class Associated Enumeration   

    /// <summary>
    /// Registering user title
    /// </summary>
    public enum UserTitle
    {
        /// <summary>
        /// Data clerk
        /// </summary>
        DATA_CLERK = 1,

        /// <summary>
        /// District Reproductive and Child Health Coordinator
        /// </summary>
        DRCHCO = 2,

        /// <summary>
        /// Region Reproductive and Child Health Coordinator
        /// </summary>
        RRCHCO = 3,

        /// <summary>
        /// Futures Group Stragetic Information Associate
        /// </summary>
        SI = 4,

        /// <summary>
        /// Others
        /// </summary>
        OTHERS = 5
    }
    #endregion

    /// <summary>
    /// Reporting Processing class. Checks the report against business rules.
    /// </summary>
    public class ReportProcessor
    {
        #region Class Variables
        private string senderNum;
        private string reportingText;
        private string registeredFacilityCode;
        //private bool senderRegistered;
        private bool resubmission;

        //private bool allowSameMonthReporting;

        private bool hasError;
        private bool invalid;
        private int errorTextLabelID;
        private string errorText;
        private ReportProcessingError errorCode;

        private string fullname;
        private string facilityName;
        //private string facilityId;
        private string reportName;

        #region Report Queries
        private int startYear;
        private int endYear;
        private int startPeriod;
        private int endPeriod;
        private string partialFacilityCode;
        #endregion

        private ReportingType type;
        private UserTitle userTitle;
        private ReportLevel reportingLevel;

        #region Report Components
        private int reportID;
        private string reportKeyword;
        private string facilityCode;
        private int period;
        private int year;
        private List<string> data;
        private List<string> reportData;
        #endregion

        private ReportingMode mode;
        private SMSReportingFormat SMSFormat;

        private bool suspectedToContainMTUHAReport = false;
        private DataInputingMethod inputMethod;
        private bool validated = false;
        private string reportComments = string.Empty;

        #region Report Processor Events
        /// <summary>
        /// Fired just before the validation process has started
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> ReportValidating;

        /// <summary>
        /// Fired after the validation process has completed
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> ReportValidated;

        /// <summary>
        /// Fired when the validation process fails
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> ReportValidationFailed;

        /// <summary>
        /// Fired before the report is submitted
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> ReportSubmitting;

        /// <summary>
        /// Fires when at least one of the business rules fails
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> ReportBussinessRulesFailed;

        /// <summary>
        /// Fired when the report is about to be saved i.e. before calling insert
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> ReportSubmitted;

        /// <summary>
        /// Fires when the report is about to be saved.
        /// </summary>
        public event EventHandler<ReportProcessorEventArgs> SavingReport;

        private ReportProcessorEventArgs e;
        #endregion
        #endregion

        #region Class Constants
        #region Supported data types
        private const string TEXT = "TEXT";
        private const string INTEGER = "INTEGER";
        private const string DECIMAL = "DECIMAL";
        #endregion

        #region User Titles
        private const int DATA_CLERK = 1;
        private const int DRCHCO = 2;
        private const int RRCHCO = 3;
        private const int SI = 4;
        private const int OTHERS = 5;
        #endregion

        #region Error Translation Text Label IDs
        public const int NO_ERROR_LABEL = 6;
        public const int REPORT_DOES_NOT_EXIST_LABEL = 35;
        public const int WHITE_SPACE_PRESENT_LABEL = 38;
        public const int INVALID_FACILITY_LABEL = 36;
        public const int INVALID_YEAR_LABEL = 23;
        public const int INVALID_PERIOD_LABEL = 24;
        public const int MISSING_FACILITY_LABEL = 37;
        public const int FEW_REPORT_PARAMETERS_LABEL = 39;
        public const int BUSINESS_RULES_FAILURE_LABEL = 7;
        public const int NON_INTEGER_VALUE_LABEL = 9;
        public const int NON_DECIMAL_VALUE_LABEL = 10;
        public const int MISSING_SENDER_NUMBER_LABEL = 42;
        public const int INVALID_REPORT_INITIALIZATION_LABEL = 44;
        public const int REPORT_IS_VERY_OLD_LABEL = 45;
        public const int REPORT_HAS_FUTURE_RECORDS_LABEL = 46;
        public const int MANY_REPORT_PARAMETERS_LABEL = 40;
        public const int INVALID_OBJECT_LABEL = 41;
        public const int SENDER_NUMBER_IS_NOT_REGISTERED_LABEL = 43;
        public const int RESUBMIT_NON_EXISTING_REPORT_LABEL = 15;
        public const int REPORT_ALREADY_SUBMITTED_LABEL = 12;
        public const int SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL = 47;
        public const int SUCH_REPORT_IS_NOT_EXPECTED_FROM_FACILITY_LABEL = 48;
        public const int INVALID_TIMEFRAME_LABEL = 53;
        public const int CURRENT_MONTH_REPORTING_NOT_ALLOWED_LABEL = 72;

        public const int UNIGOLD_IS_MISSING = 73;
        public const int DETERMINE_IS_MISSING = 74;
        public const int DBS_IS_MISSING = 75;
        public const int STOCK_MESSAGE_INVALID = 76;

        #region Comparison
        public static int COMPARISON_LABEL = 54;
        public static int EQUALS_LABEL = 60;
        public static int NOT_EQUALS_LABEL = 61;
        public static int GREATER_THAN_LABEL = 62;
        public static int GREATER_THAN_OR_EQUALS_LABEL = 63;
        public static int LESS_THAN_LABEL = 64;
        public static int LESS_THAN_OR_EQUALS_LABEL = 65;
        #endregion

        public const int MISSING_REPORTS_LABEL = 67;
        public const int MISSING_REPORT_LABEL = 68;
        #endregion

        #region Others
        private const string FACCODE = "FACCODE";
        private const string MONTH = "MONTH";
        private const string YEAR = "YEAR";
        #endregion

        #region Configuration/Settings name
        public const string SETTING_MTUHA_MC_REPORT = "MTUHA_MC_REPORT_ID";
        public const string SETTING_NORMAL_MC_REPORT = "NORMAL_MC_REPORT_ID";

        public const string SETTING_NORMAL_ANC_REPORTS = "SETTING_NORMAL_ANC_REPORTS";
        public const string SETTING_NORMAL_PCR_REPORTS = "SETTING_NORMAL_PCR_REPORTS";
        public const string HANDLE_INCONSISTENT_REPORTS = "HANDLE_INCONSISTENT_REPORTS";
        #endregion

        /// <summary>
        /// we never accept anything less than this year. 
        /// Also to avoid zero year
        /// </summary>
        private const int BASELINE_YEAR = 1961;
        private const int UPPER_LIMIT_YEAR = 2050;  //why this number?!, dah!... it looks good on consolas

        /// <summary>
        /// This is the number of indicators i.e. 19 plus the facility code, report year and month
        /// </summary>
        private const int MTUHA_MC_REPORT_NUMBER_OF_INDICATORS = 22;
        #endregion

        #region Constructors
        /// <summary>
        /// Creates an invalid report processing object
        /// </summary>
        private ReportProcessor(/*bool allowSameMonthReporting*/ ReportingMode mode)
        {
            this.senderNum = String.Empty;
            this.reportingText = String.Empty;
            this.invalid = true;
            this.hasError = true;
            this.errorCode = ReportProcessingError.INVALID_OBJECT;
            this.errorTextLabelID = INVALID_OBJECT_LABEL;
            this.userTitle = UserTitle.DATA_CLERK;
            this.errorText = Utilities.GetTranslationText("IQSMSM", INVALID_OBJECT_LABEL);
            this.reportingLevel = ReportLevel.FACILITY;
            //this.allowSameMonthReporting = allowSameMonthReporting;
            this.mode = mode;

            this.SMSFormat = SMSReportingFormat.RESTRICTIVE;
        }

        /// <summary>
        /// Creates Report Processing object based on reporting text reportingText
        /// </summary>
        /// <param name="senderNum">Sender's cell phone number</param>
        /// <param name="reportingText">Reporting text from SMS without REP. keyword</param>
        public ReportProcessor(string senderNum, string reportingText, /*bool allowSameMonthReporting*/ ReportingMode mode,
            SMSReportingFormat SMSFormat, DataInputingMethod inputMethod, string comments = null)
        {
            this.senderNum = senderNum;
            this.reportingText = reportingText;
            //this.senderRegistered = false;
            this.resubmission = false;
            this.facilityName = String.Empty;
            this.fullname = String.Empty;
            this.registeredFacilityCode = String.Empty;
            this.reportData = new List<string>();
            this.hasError = false;
            this.invalid = false;
            this.errorCode = ReportProcessingError.NO_ERROR;
            this.errorTextLabelID = NO_ERROR_LABEL;
            this.errorText = Utilities.GetTranslationText(this.senderNum, NO_ERROR_LABEL);
            this.type = ReportingType.SENDING;
            this.userTitle = UserTitle.DATA_CLERK;
            this.reportingLevel = ReportLevel.FACILITY;
            this.SMSFormat = SMSFormat;
            this.inputMethod = inputMethod;
            this.reportComments = comments;

            //this.allowSameMonthReporting = allowSameMonthReporting;
            this.mode = mode;

            e = new ReportProcessorEventArgs();
            e.SenderNumber = this.senderNum;
            e.OriginalText = this.reportingText;
            e.ReportingType = this.type;
            e.DataInputingMethod = this.inputMethod;
            e.ReportingMode = this.mode;
            e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);

            //try
            //{
            //    Validate();
            //}
            //catch (Exception ex)
            //{
            //    Utilities.LogError(ex, null);
            //    this.hasError = true;
            //    this.invalid = true;
            //    this.errorCode = ReportProcessingError.INVALID_REPORT_INITIALIZATION;
            //    this.errorTextLabelID = INVALID_REPORT_INITIALIZATION_LABEL;
            //    this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_REPORT_INITIALIZATION_LABEL);
            //}
        }

        /// <summary>
        /// Creates Report Processing object based on reporting text reportingText
        /// </summary>
        /// <param name="senderNum">Sender's cell phone number</param>
        /// <param name="reportingQuery">Reporting text from SMS without REP. keyword</param>
        /// <param name="type">Type of report processing requested</param>
        public ReportProcessor(string senderNum, string reportingQuery,
            ReportingType type, /*bool allowSameMonthReporting*/ ReportingMode mode,
            SMSReportingFormat SMSFormat, DataInputingMethod inputMethod, string comments = null)
        {
            this.senderNum = senderNum;
            this.reportingText = reportingQuery;
            //this.senderRegistered = false;
            this.resubmission = false;
            this.facilityName = String.Empty;
            this.fullname = String.Empty;
            this.registeredFacilityCode = String.Empty;
            this.reportData = new List<string>();
            this.hasError = false;
            this.invalid = false;
            this.errorCode = ReportProcessingError.NO_ERROR;
            this.errorTextLabelID = NO_ERROR_LABEL;
            this.errorText = Utilities.GetTranslationText(this.senderNum, NO_ERROR_LABEL);
            this.type = type;
            this.reportingLevel = ReportLevel.FACILITY;
            this.SMSFormat = SMSFormat;
            this.inputMethod = inputMethod;
            this.reportComments = comments;

            //this.allowSameMonthReporting = allowSameMonthReporting;
            this.mode = mode;
            //try
            //{
            //    Validate();
            //}
            //catch (Exception ex)
            //{
            //    Utilities.LogError(ex, null);
            //    this.hasError = true;
            //    this.invalid = true;
            //    this.errorCode = ReportProcessingError.INVALID_REPORT_INITIALIZATION;
            //    this.errorTextLabelID = INVALID_REPORT_INITIALIZATION_LABEL;
            //    this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_REPORT_INITIALIZATION_LABEL);
            //}

            e = new ReportProcessorEventArgs();
            e.SenderNumber = this.senderNum;
            e.OriginalText = this.reportingText;
            e.ReportingType = this.type;
            e.DataInputingMethod = this.inputMethod;
            e.ReportingMode = this.mode;
            e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
        }

        public ReportProcessor(string senderNum, List<string> resolvedDataComponents,
            ReportingType type, /*bool allowSameMonthReporting*/ ReportingMode mode,
            SMSReportingFormat SMSFormat, DataInputingMethod inputMethod, string comments = null)
        {
            if (resolvedDataComponents.Count < 4)
            {
                throw new ArgumentOutOfRangeException("Resolved Data Components has few indicators");
            }

            StringBuilder sBuilder = new StringBuilder();
            sBuilder.Append(resolvedDataComponents[0] + ".");   // Keyword
            sBuilder.Append(resolvedDataComponents[1]); // Initial entry to fix loop with ','
            for (int i = 2; i < resolvedDataComponents.Count; i++)
            {
                string indicator = resolvedDataComponents[i];
                sBuilder.Append("," + indicator);
            }

            string recreatedText = sBuilder.ToString();
            this.senderNum = senderNum;
            this.reportingText = recreatedText;
            //this.senderRegistered = false;
            this.resubmission = false;
            this.facilityName = String.Empty;
            this.fullname = String.Empty;
            this.registeredFacilityCode = String.Empty;
            this.reportData = new List<string>();
            this.hasError = false;
            this.invalid = false;
            this.errorCode = ReportProcessingError.NO_ERROR;
            this.errorTextLabelID = NO_ERROR_LABEL;
            this.errorText = Utilities.GetTranslationText(this.senderNum, NO_ERROR_LABEL);
            this.type = type;
            this.reportingLevel = ReportLevel.FACILITY;
            this.SMSFormat = SMSFormat;
            this.inputMethod = inputMethod;
            this.reportComments = comments;

            //this.allowSameMonthReporting = allowSameMonthReporting;
            this.mode = mode;
            //try
            //{
            //    Validate();
            //}
            //catch (Exception ex)
            //{
            //    Utilities.LogError(ex, null);
            //    this.hasError = true;
            //    this.invalid = true;
            //    this.errorCode = ReportProcessingError.INVALID_REPORT_INITIALIZATION;
            //    this.errorTextLabelID = INVALID_REPORT_INITIALIZATION_LABEL;
            //    this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_REPORT_INITIALIZATION_LABEL);
            //}

            e = new ReportProcessorEventArgs();
            e.SenderNumber = this.senderNum;
            e.OriginalText = this.reportingText;
            e.ReportingType = this.type;
            e.DataInputingMethod = this.inputMethod;
            e.ReportingMode = this.mode;
            e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets sender number used to create this object
        /// </summary>
        public string SenderNum
        {
            get
            {
                if (!validated) Validate();
                return this.senderNum;
            }
        }

        /// <summary>
        /// Gets reporting text used to create this object
        /// </summary>
        public string ReportingText
        {
            get
            {
                if (!validated) Validate();
                return this.reportingText;
            }
        }

        /// <summary>
        /// Gets report processing error code/status of this object
        /// </summary>
        public ReportProcessingError Error
        {
            get
            {
                if (!validated) Validate();
                return this.errorCode;
            }
        }

        /// <summary>
        /// Gets validity status of this object
        /// </summary>
        public bool Valid
        {
            get
            {
                if (!validated) Validate();
                return !invalid;
            }
        }

        /// <summary>
        /// True if the object has report processing errors otherwise false
        /// </summary>
        public bool HasError
        {
            get
            {
                if (!validated) Validate();
                return hasError;
            }
        }

        /// <summary>
        /// Gets registered user fullname
        /// </summary>
        public string RegisteredFullname
        {
            get
            {
                if (!validated) Validate();
                return this.fullname;
            }
        }

        /// <summary>
        /// Gets registered user facility name
        /// </summary>
        public string RegisteredFacilityName
        {
            get
            {
                if (!validated) Validate();
                return this.facilityName;
            }
        }

        /// <summary>
        /// Translation text label ID associated with the error in this object
        /// </summary>
        public int ErrorTextLabelID
        {
            get
            {
                if (!validated) Validate();
                return this.errorTextLabelID;
            }
        }

        /// <summary>
        /// Text associated with the error in this object
        /// </summary>
        public string ErrorText
        {
            get
            {
                if (!validated) Validate();
                return this.errorText;
            }
        }

        public string FacilityCode
        {
            get
            {
                if (!validated) Validate();
                if (this.facilityCode != null) return this.facilityCode;
                else return this.partialFacilityCode;
            }
        }

        public int Period
        {
            get
            {
                if (!validated) Validate();
                return this.period;
            }
        }

        public int Year
        {
            get
            {
                if (!validated) Validate();
                return this.year;
            }
        }

        public int ReportID
        {
            get
            {
                if (!validated) Validate();
                return this.reportID;
            }
        }

        public ReportingMode Mode
        {
            get
            {
                if (!validated) Validate();
                return this.mode;
            }
            set
            {
                this.mode = value;
            }
        }

        public List<int> ReportData
        {
            get
            {
                if (!validated) Validate();
                var list = new List<int>();
                int value;
                foreach (var d in this.data)
                {
                    bool converted = int.TryParse(d, out value);
                    if (converted) list.Add(value);
                    else
                    {
                        list.Clear();
                        break;
                    }
                }
                return list;
            }
        }
        #endregion

        #region Public Methods
        public void Validate()
        {
            if (!validated) validated = true;
            if (ReportValidating != null) ReportValidating(this, e);

            try
            {
                // Skip sender number checking if the object is just for validation
                if (type != ReportingType.VALIDATION) //this.senderRegistered = true;
                //else
                {
                    // Validating sender number
                    if (String.IsNullOrEmpty(senderNum))
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.MISSING_SENDER_NUMBER;
                        this.errorTextLabelID = MISSING_SENDER_NUMBER_LABEL;
                        this.errorText = Utilities.GetTranslationText("MISSING", MISSING_SENDER_NUMBER_LABEL);

                        e.Status = ReportingError.GetReportingError(this.errorCode);
                        //TODO: Fire event when sendernum is missing
                        return;
                    }

                    bool registered = IsUserRegistered();
                    if (!registered) //this.senderRegistered = true;
                    //else
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.SENDER_NUMBER_IS_NOT_REGISTERED;
                        this.errorTextLabelID = SENDER_NUMBER_IS_NOT_REGISTERED_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum, SENDER_NUMBER_IS_NOT_REGISTERED_LABEL);

                        e.Status = ReportingError.GetReportingError(this.errorCode);
                        //TODO: Fire event when user is not registered.
                        return;
                    }

                    // Only users registered for facility can send reports
                    if ((this.userTitle != UserTitle.DATA_CLERK) && (type == ReportingType.SENDING))
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY;
                        this.errorTextLabelID = SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum, SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL);

                        e.Status = ReportingError.GetReportingError(this.errorCode);
                        //TODO: Fire event when user is not registered in selected facility
                        return;
                    }
                }

                // Removing white spaces
                reportingText = reportingText.Replace(" ", "");
                reportingText = reportingText.Replace("\t", "");
                reportingText = reportingText.Replace("\n", "");

                // Validating reporting text
                ValidateReportingText(reportingText);

                if (this.hasError) if (ReportValidationFailed != null) ReportValidationFailed(this, e);
                if (ReportValidated != null) ReportValidated(this, e);
            }
            catch (Exception ex)
            {
                Utilities.LogError(ex, null);
                this.hasError = true;
                this.invalid = true;
                this.errorCode = ReportProcessingError.INVALID_REPORT_INITIALIZATION;
                this.errorTextLabelID = INVALID_REPORT_INITIALIZATION_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_REPORT_INITIALIZATION_LABEL);
            }
        }

        /// <summary>
        /// Submit the report after full validation.
        /// </summary>
        /// <returns>True if saved successfully otherwise false</returns>
        public bool Submit()
        {
            if (!validated) Validate();

            //TODO: Why start by assuming few report parameters?
            //this.errorCode = ReportProcessingError.FEW_REPORT_PARAMETERS;
            //this.errorTextLabelID = FEW_REPORT_PARAMETERS_LABEL;
            //this.errorText = Services.GetTranslationText(this.senderNum, FEW_REPORT_PARAMETERS_LABEL);

            if (type == ReportingType.REQUEST) return false;
            // TODO: For some reason Merging class wants the next line turned off
            //if (type == ReportingType.VALIDATION) return false;
            
            if (this.hasError)
            {
                var e = TryToLookForMTUHAReport();
                if (e == null) return false;

                if (e.ReportingError.Type == ReportProcessingError.NO_ERROR)
                {
                    this.hasError = false;
                    this.errorCode = e.ReportingError.Type;
                    this.errorText = e.ReportingError.ErrorText;
                    this.facilityCode = e.FacilityCode;
                    this.period = e.ReportMonth;
                    this.suspectedToContainMTUHAReport = true;
                    this.year = e.ReportYear;
                    return true;
                }
                else
                {
                    // Decide which error to display, normal ANC or MTUHA based
                    bool useClassicErrors = UseClassicFormError(e.ReportingError.Type);
                    if (!useClassicErrors)
                    {
                        this.errorCode = e.ReportingError.Type;
                        this.errorText = e.ReportingError.ErrorText;
                    }

                    //if (this.errorCode == ReportProcessingError.NON_INTEGER_VALUE)
                    //{
                    //    this.errorCode = e.ReportingError.Type;
                    //    this.errorText = e.ReportingError.ErrorText;
                    //}
                    //if (this.errorCode == ReportProcessingError.SUCH_REPORT_IS_NOT_EXPECTED_FROM_FACILITY)
                    //{
                    //    this.errorCode = e.ReportingError.Type;
                    //    this.errorText = e.ReportingError.ErrorText;
                    //}
                    return false;
                }
            }
            else
            {
                bool status = false;
                status = SubmitReport();
                if (status)
                {
                    // Here we will try to save this report in other formats.
                    // But we don't want this operation to break any operation
                    // sequence
                    try
                    {
                        TryToSaveIntoMTUHAReport();
                        //bool savedInMTUHA = TryToSaveIntoMTUHAReport();
                        //if (!savedInMTUHA)
                        //{
                        //    string errorMessage = string.Format("Failed to Save to MTUHA: {0}", this.ReportingText);
                        //    var ex = new Exception(errorMessage);
                        //    Utilities.LogError(ex, null);
                        //}
                    }
                    catch { }
                }
                else
                {
                    var e = TryToLookForMTUHAReport();
                    if (e != null)
                    {
                        if (e.ReportingError.Type == ReportProcessingError.NO_ERROR)
                        {
                            this.hasError = false;
                            status = true;
                        }
                        else
                        {
                            // Decide which error to display, normal ANC or MTUHA based
                            if (this.errorCode == ReportProcessingError.NON_INTEGER_VALUE)
                            {
                                this.errorCode = e.ReportingError.Type;
                                this.errorText = e.ReportingError.ErrorText;
                            }
                        }
                    }
                }
                return status;
            }
        }

        private bool UseClassicFormError(ReportProcessingError ancFormError)
        {
            if (this.reportingText.Contains('K') || this.reportingText.Contains('k')) return false;
            if (this.reportingText.Contains(",C") || this.reportingText.Contains(",c")) return false;
            
            return true;
        }

        public string GetReport()
        {
            if (!validated) Validate();
            string result = String.Empty;

            if (this.hasError) return result;
            if (type == ReportingType.SENDING) return result;

            DataTable dataTable = GetReportData();
            if (dataTable.Rows.Count > 0)
            {
                //TODO: Structure the report...
                string template = "{0}: {1} {2} - {3} {4}: {5}";
                StringBuilder sBuilder = new StringBuilder();
                foreach (DataRow row in dataTable.Rows)
                {
                    int data = Int32.Parse(row["ReportData"].ToString());
                    string code = row["ShortCode"].ToString();
                    sBuilder.Append(code);
                    sBuilder.Append("=");
                    sBuilder.Append(data);
                    sBuilder.Append(",");
                }
                string sData = sBuilder.ToString();
                int length = sData.LastIndexOf(',');
                sData = sData.Substring(0, length);
                result = String.Format(template,
                    this.facilityName,
                    Utilities.GetMonthText(this.startPeriod),
                    this.startYear,
                    Utilities.GetMonthText(this.endPeriod),
                    this.endYear,
                    sData);

                DataTable missingReports = null;
                string id = String.Empty;
                switch (this.reportingLevel)
                {
                    case ReportLevel.FACILITY:
                        missingReports = Utilities.GetMissingFacilityReport(
                            this.partialFacilityCode, this.reportID, this.startYear,
                            this.startPeriod, this.endYear, this.endPeriod);
                        break;

                    case ReportLevel.DISTRICT:
                        id = Utilities.GetID(this.facilityName, ReportLevel.DISTRICT);
                        int districtID = Int32.Parse(id);
                        missingReports = Utilities.GetMissingDistrictReport(districtID,
                            this.reportID, this.startYear, this.startPeriod, this.endYear,
                            this.endPeriod);
                        break;

                    case ReportLevel.REGION:
                        id = Utilities.GetID(this.facilityName, ReportLevel.REGION);
                        int regionID = Int32.Parse(id);
                        missingReports = Utilities.GetMissingRegionReport(
                            regionID, this.reportID, this.startYear, startPeriod,
                            endYear, endPeriod);
                        break;
                }
                int count = missingReports.Rows.Count;
                if (count > 0)
                {
                    int labelID = (count == 1) ? MISSING_REPORT_LABEL : MISSING_REPORTS_LABEL;
                    string missing = Utilities.GetTranslationText(this.senderNum, labelID);
                    missing = String.Format(missing, count);
                    result = String.Format("{0}. {1}", result, missing);
                }

                return result;
            }
            else
            {
                result = "Requested Report is not available";
            }
            return result;
        }

        public static ReportingError ProcessStockReportingMessage(string phoneNumber, string message,
            string possibleReplyMessage, int possibleReplyErrorCode, out bool hasError,
            SMSReportingFormat format = SMSReportingFormat.FLEXIBLE)
        {
            string outputMessage = String.Empty;
            var reportingError = ReportingError.GetReportingError(possibleReplyErrorCode, phoneNumber);
            reportingError.ErrorText = possibleReplyMessage;

            hasError = true;

            if (format == SMSReportingFormat.FLEXIBLE || format == SMSReportingFormat.HIGHLY_ADAPTIVE)
            {
                message = message.Replace(".", ",");
            }

            #region Preliminary Checks
            string[] parts = message.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length != 5)
            {
                message = message.ToUpper();
                // TODO: You need a better way to deal with this.
                if (message.StartsWith("ANC") || message.StartsWith("PCR")
                    || message.StartsWith("MAT") || message.StartsWith("MC"))
                {
                    hasError = true;
                    //return possibleReplyMessage;
                    return reportingError;
                }
                else
                {
                    hasError = true;
                    //return Utilities.GetTranslationText(phoneNumber, ReportProcessor.STOCK_MESSAGE_INVALID);
                    return ReportingError.GetReportingError(ReportProcessingError.STOCK_MESSAGE_INVALID, phoneNumber);
                }
            }
            #endregion

            #region Validating Month and Year
            int period = -1;
            int year = -1;
            string errorText = String.Empty;
            bool okToContinue = ReportProcessor.ValidatePeriod(parts[0], out period, out errorText);
            if (okToContinue)
            {
                ReportingMode mode = ReportingMode.DEFAULT;
                int generateErrorCode = default(int);
                okToContinue = ReportProcessor.ValidateMonthAndYear(parts[1], period, mode, 
                    out year, out errorText,  out generateErrorCode);
                if (!okToContinue)
                {
                    hasError = true;
                    outputMessage = errorText;
                    reportingError = ReportingError.GetReportingError(generateErrorCode, phoneNumber);
                    reportingError.ErrorText = outputMessage;
                    //return outputMessage;
                    return reportingError;
                }
            }
            else
            {
                hasError = true;
                outputMessage = errorText;
                reportingError = ReportingError.GetReportingError(ReportingError.INVALID_PERIOD_LABEL, phoneNumber);
                reportingError.ErrorText = outputMessage;
                //return outputMessage;
                return reportingError;
            }
            #endregion

            #region Validating Data Components
            int unigold = -1;
            int determine = -1;
            int dbs = -1;
            for (int i = 2; i < parts.Length; i++)
            {
                string part = parts[i];
                string tool = part.ToUpper();
                tool = tool.Trim();
                #region If Unigold
                if (tool.StartsWith("UN"))
                {
                    string sUnigold = Regex.Replace(tool, @"[^\d]", "");
                    if (String.IsNullOrEmpty(sUnigold))
                    {
                        hasError = true;
                        //outputMessage = Utilities.GetTranslationText(phoneNumber, ReportProcessor.UNIGOLD_IS_MISSING);
                        reportingError = ReportingError.GetReportingError(ReportingError.UNIGOLD_IS_MISSING_LABEL, phoneNumber);
                        return reportingError;
                        //return outputMessage;
                    }
                    else
                    {
                        unigold = Int32.Parse(sUnigold);
                    }
                }
                #endregion
                #region If Determine
                if (tool.StartsWith("DT"))
                {
                    string sDetermine = Regex.Replace(tool, @"[^\d]", "");
                    if (String.IsNullOrEmpty(sDetermine))
                    {
                        hasError = true;
                        //outputMessage = Utilities.GetTranslationText(phoneNumber, ReportProcessor.DETERMINE_IS_MISSING);
                        //return outputMessage;
                        reportingError = ReportingError.GetReportingError(ReportingError.DETERMINE_IS_MISSING_LABEL, phoneNumber);
                        return reportingError;
                    }
                    else
                    {
                        determine = Int32.Parse(sDetermine);
                    }
                }
                #endregion
                #region If DBS
                if (tool.StartsWith("DB"))
                {
                    string sDBS = Regex.Replace(tool, @"[^\d]", "");
                    if (String.IsNullOrEmpty(sDBS))
                    {
                        hasError = true;
                        //outputMessage = Utilities.GetTranslationText(phoneNumber, ReportProcessor.DBS_IS_MISSING);
                        //return outputMessage;
                        reportingError = ReportingError.GetReportingError(ReportingError.DBS_IS_MISSING_LABEL, phoneNumber);
                        return reportingError;
                    }
                    else
                    {
                        dbs = Int32.Parse(sDBS);
                    }
                }
                #endregion
            }
            #endregion

            #region Saving Stock Data
            hasError = true;
            if (unigold == -1) return ReportingError.GetReportingError(ReportProcessor.UNIGOLD_IS_MISSING, phoneNumber);
            if (dbs == -1) return ReportingError.GetReportingError(ReportProcessor.DBS_IS_MISSING, phoneNumber);
            if (determine == -1) return ReportingError.GetReportingError(ReportProcessor.DETERMINE_IS_MISSING, phoneNumber);

            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT [Name], [FacCode], [TitleID] FROM ApprovedSMSCells WHERE (CellNum = @SenderNum)";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@Sendernum";
            param.DbType = DbType.String;
            param.Value = phoneNumber;
            command.Parameters.Add(param);

            DataTable dataTable = GenericDataAccess.ExecuteSelectCommand(command);
            if (dataTable.Rows.Count == 1)
            {
                DataRow row = dataTable.Rows[0];
                string facilityCode = row["FacCode"].ToString();
                SaveTestKitDataIntoItsTable(facilityCode, period, year, determine, unigold, dbs);

                #region Inserting the stock data into the usual report templates
                command.CommandText = String.Format("SELECT RepVersion FROM Report WHERE RepID={0}", AppConfiguration.StockReportID);
                string reportKeyword = GenericDataAccess.ExecuteScalar(command);
                string reportingText = String.Format("{0}.{1},{2},{3},{4},{5},{6}",
                    reportKeyword, facilityCode, period, year, determine, unigold, dbs);

                SMSReportingFormat SMSFormat = SMSReportingFormat.FLEXIBLE;
                DataInputingMethod inputMethod = DataInputingMethod.SMS;
                ReportingMessage reportingMessage = Merging.SendReport(phoneNumber, reportingText,
                    SMSFormat, inputMethod);
                if (reportingMessage.Status == ReportProcessing.ReportProcessor.REPORT_ALREADY_SUBMITTED_LABEL)
                {
                    reportingText = String.Format("{0},RESUBMIT", reportingText);
                    Merging.SendReport(phoneNumber, reportingText, SMSFormat, inputMethod);
                }
                #endregion

                hasError = false;
                //outputMessage = Utilities.GetTranslationText(phoneNumber, ReportProcessor.NO_ERROR_LABEL);
                //return outputMessage;
                reportingError = ReportingError.GetReportingError(ReportingError.NO_ERROR_LABEL, phoneNumber);
                return reportingError;
            }
            else
            {
                hasError = true;
                //outputMessage = Utilities.GetTranslationText(phoneNumber, ReportProcessor.SENDER_NUMBER_IS_NOT_REGISTERED_LABEL);
                //return outputMessage;
                reportingError = ReportingError.GetReportingError(ReportingError.SENDER_NUMBER_IS_NOT_REGISTERED_LABEL, phoneNumber);
                return reportingError;
            }
            #endregion
        }

        private static void SaveTestKitDataIntoItsTable(string facilityCode, int month, 
            int year, int determine, int unigold, int dbs)
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandText = @"DELETE FROM StockStatus WHERE (FacCode = @FacCode)
                    AND (ReportYear=@ReportYear) AND (ReportMonth=@ReportMonth)";
            DbParameter param = command.CreateParameter();
            param.ParameterName = "@FacCode";
            param.DbType = DbType.String;
            param.Value = facilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportYear";
            param.DbType = DbType.Int32;
            param.Value = year;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportMonth";
            param.DbType = DbType.Int32;
            param.Value = month;
            command.Parameters.Add(param);
            GenericDataAccess.ExecuteNonQuery(command);

            command = GenericDataAccess.CreateCommand();
            command.CommandText = @"INSERT INTO StockStatus(FacCode, RequiredDetermine, RequiredUnigold, 
                    RequiredDBS, DateReportReceived, ReportDate, ReportYear, ReportMonth) 
                    VALUES (@FacCode, @RequiredDetermine, @RequiredUnigold, @RequiredDBS, @DateReportReceived, 
                    @ReportDate, @ReportYear, @ReportMonth)";
            param = command.CreateParameter();
            param.ParameterName = "@FacCode";
            param.DbType = DbType.String;
            param.Value = facilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@RequiredDetermine";
            param.DbType = DbType.Int32;
            param.Value = determine;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@RequiredUnigold";
            param.DbType = DbType.Int32;
            param.Value = unigold;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@RequiredDBS";
            param.DbType = DbType.Int32;
            param.Value = dbs;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportYear";
            param.DbType = DbType.Int32;
            param.Value = year;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportMonth";
            param.DbType = DbType.Int32;
            param.Value = month;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@DateReportReceived";
            param.DbType = DbType.DateTime;
            param.Value = DateTime.Now;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportDate";
            param.DbType = DbType.DateTime;
            param.Value = DateTime.Parse(String.Format("{0}-{1}-1", year, month));
            command.Parameters.Add(param);
            GenericDataAccess.ExecuteNonQuery(command, false);
        }

        #region Class in-build event handlers
        public static void HandleMTUHAMCReport(object sender, ReportProcessorEventArgs e)
        {
            // We deal with this here if and only if the report being evaluated is MTUHA MC
            // report (and it has 19 indicators)
            if (e.ResolvedDataElements.Count == MTUHA_MC_REPORT_NUMBER_OF_INDICATORS)
            {
                // First we change the target report
                string normalMCReportId = Utilities.GetSetting(SETTING_NORMAL_MC_REPORT);
                int iNormalMCReportId;
                bool converted = int.TryParse(normalMCReportId, out iNormalMCReportId);
                if (converted)
                {
                    if (e.ReportId == iNormalMCReportId)
                    {
                        string MTUHAMCReportId = Utilities.GetSetting(SETTING_MTUHA_MC_REPORT);
                        int iMTUHAMCReportId;
                        converted = int.TryParse(MTUHAMCReportId, out iMTUHAMCReportId);
                        if (converted)
                        {
                            e.ReportId = iMTUHAMCReportId;
                            e.ReEvaluate = true;
                        }
                    }
                }
            }            
        }

        /// <summary>
        /// The main purpose of this event is to handle the old ANC report
        /// it will deal with ANC06, ANC07 and ANC08 realocation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public static void HandleInconsitentReports(object sender, ReportProcessorEventArgs e)
        {
            string setting = Utilities.GetSetting(HANDLE_INCONSISTENT_REPORTS);
            if (string.IsNullOrWhiteSpace(setting)) return;
            bool handleInconsitentReports;
            bool converted = bool.TryParse(setting, out handleInconsitentReports);
            if (!converted) return;
            
            if (handleInconsitentReports)
            {
                // To prevent possible infinity loop if at all exists...
                ReportProcessor parentProcessor = sender as ReportProcessor;
                if (parentProcessor == null) throw new InvalidOperationException("This method is associated with instances Report Processor only");
                if (parentProcessor.type == ReportingType.VALIDATION) return;   // Validation within validation???

                List<int> ancReportIds = new List<int>();
                List<int> pcrReportIds = new List<int>();
                setting = Utilities.GetSetting(SETTING_NORMAL_ANC_REPORTS);
                if (!string.IsNullOrWhiteSpace(setting))
                {
                    string[] components = setting.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (var component in components)
                    {
                        int value;
                        converted = int.TryParse(component, out value);
                        if (converted) ancReportIds.Add(value);
                    }
                }

                bool isANCReport = false;
                foreach (var id in ancReportIds)
                {
                    if (id == e.ReportId)
                    {
                        isANCReport = true;
                        break;
                    }
                }

                if (isANCReport)
                {
                    string firstTested = e.ResolvedDataElements[6];
                    string firstCounseled = e.ResolvedDataElements[8];
                    string secondTested = e.ResolvedDataElements[9];
                    string secondCounseled = e.ResolvedDataElements[11];
                    
                    if ((firstTested == firstCounseled) && (secondTested == secondCounseled))
                    {
                        // Here we are going to check the ANC inconsistence
                        // The target is on ANC06, ANC07 and ANC08
                        // The trick is based on existing existing business rules.
                        // If we pretend this report is already inconsistent, then our attempt to
                        // fix should be accepted, otherwise the reports is correct!!! Haaahaaa or may be?!
                        string anc06 = e.ResolvedDataElements[8];
                        string anc07 = e.ResolvedDataElements[9];
                        string anc08 = e.ResolvedDataElements[10];

                        var reportParts = new List<string>();
                        reportParts.Add(e.ReportKeyword);
                        foreach (var i in e.ResolvedDataElements) reportParts.Add(i);
                        // Now fixing part
                        reportParts[8] = anc07;
                        reportParts[9] = anc08;
                        reportParts[10] = anc06;

                        var processor = new ReportProcessor(e.SenderNumber, reportParts,
                            ReportingType.VALIDATION, ReportingMode.DEFAULT, SMSReportingFormat.FLEXIBLE,
                            DataInputingMethod.OTHER_METHODS);
                        if (processor.Valid)
                        {
                            // This report is the potential report inconsistence, 
                            // so we're going to fix it if we're sure First tested and those given
                            // counseling are the same. The same principle applies to second test
                            // as well.
                            e.ResolvedDataElements[8] = anc07;
                            e.ResolvedDataElements[9] = anc08;
                            e.ResolvedDataElements[10] = anc06;
                        }
                    }                    
                }
            }
        }
        #endregion

        #endregion

        #region Private Helper Methods

        private FormValidator TryToLookForMTUHAReport()
        {
            string ancReportKeyword = Utilities.GetSetting(ANCFormValidator.SETTINGS_KEY_ANC_MTUHA_REPORT_KEYWORDS);
            if (string.IsNullOrEmpty(ancReportKeyword))
            {
                Utilities.SetSetting(ANCFormValidator.SETTINGS_KEY_ANC_MTUHA_REPORT_KEYWORDS, ANCFormValidator.DEFAULT_ANC_MTUHA_REPORT_KEYWORDS);
                ancReportKeyword = ANCFormValidator.DEFAULT_ANC_MTUHA_REPORT_KEYWORDS;
            }

            string matReportKeyword = Utilities.GetSetting(LDFormValidator.SETTINGS_KEY_LD_MTUHA_REPORT_KEYWORDS);
            if (string.IsNullOrEmpty(matReportKeyword))
            {
                Utilities.SetSetting(LDFormValidator.SETTINGS_KEY_LD_MTUHA_REPORT_KEYWORDS, LDFormValidator.DEFAULT_LD_MTUHA_REPORT_KEYWORDS);
                matReportKeyword = LDFormValidator.DEFAULT_LD_MTUHA_REPORT_KEYWORDS;
            }

            string ancKeyword = ancReportKeyword.Split('|')[0];
            string matKeyword = matReportKeyword.Split('|')[0];

            FormValidator mtuha = null;
            if (reportingText.StartsWith(ancKeyword, StringComparison.OrdinalIgnoreCase))
            {
                mtuha = new ANCFormValidator(this.reportingText, this.senderNum,
                SMSReportingFormat.HIGHLY_ADAPTIVE, this.mode, this.inputMethod, null, false);
            }

            if (reportingText.StartsWith(matKeyword, StringComparison.OrdinalIgnoreCase))
            {
                mtuha = new LDFormValidator(this.reportingText, this.senderNum,
                SMSReportingFormat.HIGHLY_ADAPTIVE, this.mode, this.inputMethod, null, false);
            }

            if (mtuha != null)
            {
                bool correct = mtuha.Validate();
                if (correct) mtuha.Save();
            }

            return mtuha;
        }

        private bool TryToSaveIntoMTUHAReport()
        {
            int WITHOUT_KEYWORD_CLASSIC_REPORT_DATA_START_INDEX = 3;

            string sectionKeyword = Utilities.GetSetting(ANCFormValidator.SETTINGS_KEY_MTUHA_REPORT_SECTION_KEYWORD);
            string under20Keyword = Utilities.GetSetting(ANCFormValidator.SETTINGS_KEY_MTUHA_REPORT_UNDER_20_KEYWORD);
            string above20Keyword = Utilities.GetSetting(ANCFormValidator.SETTINGS_KEY_MTUHA_REPORT_ABOVE_20_KEYWORD);

            string targetAgeKeyword = string.Empty;
            string targetSectionKeyword = string.Empty;

            bool ageKeywordFound = false;
            if (this.reportKeyword.ToLower().Contains(under20Keyword.ToLower()))
            {
                ageKeywordFound = true;
                targetAgeKeyword = under20Keyword;
            }

            if (this.reportKeyword.ToLower().Contains(above20Keyword.ToLower()))
            {
                ageKeywordFound = true;
                targetAgeKeyword = above20Keyword;
            }

            if (!ageKeywordFound) return false;

            bool sectionKeywordFound = false;
            bool okToContinue = false;
            if (this.reportKeyword.ToLower().Contains(sectionKeyword.ToLower()))
            {
                sectionKeywordFound = true;
                string capitalKeyword = this.reportKeyword.ToUpper();
                string capitalAgeKeyword = targetAgeKeyword.ToUpper();
                string section = capitalKeyword.Replace(capitalAgeKeyword, "");

                string capitalSectionKeyword = sectionKeyword.ToUpper();
                section = section.Replace(capitalSectionKeyword, "");

                int sectionNumber;
                okToContinue = int.TryParse(section, out sectionNumber);
                if (okToContinue) targetSectionKeyword = string.Format("{0}{1}", capitalSectionKeyword, sectionNumber);
                else return false;
            }

            if (!sectionKeywordFound) return false;

            string targetKeywords = GenericTools.Utilities.GetSetting(ANCFormValidator.SETTINGS_KEY_ANC_MTUHA_REPORT_KEYWORDS);
            string targetReportKeyword = targetKeywords.Split('|')[0];
            StringBuilder sBuilder = new StringBuilder();
            sBuilder.Append(targetReportKeyword);
            sBuilder.Append("." + this.FacilityCode);
            sBuilder.Append("," + this.Period + "," + this.Year);
            sBuilder.Append("," + targetAgeKeyword + "," + targetSectionKeyword);

            bool converted = true;
            for (int i = WITHOUT_KEYWORD_CLASSIC_REPORT_DATA_START_INDEX; i < this.reportData.Count; i++)
            {
                int value;
                converted = int.TryParse(this.reportData[i], out value);
                if (converted) sBuilder.Append("," + value);
                else return false;
            }

            string text = sBuilder.ToString();
            var mtuha = new ANCFormValidator(text, this.senderNum,
                SMSReportingFormat.HIGHLY_ADAPTIVE, this.mode, this.inputMethod, null, false);
            bool correct = mtuha.Validate();
            if (correct)
            {
                bool saved = mtuha.Save();
                return saved;
            }
            else return false;
        }

        private bool IsUserRegistered()
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT [Name], [FacCode], [TitleID] FROM ApprovedSMSCells WHERE (CellNum = @SenderNum)";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@Sendernum";
            param.DbType = DbType.String;
            param.Value = this.senderNum;
            command.Parameters.Add(param);

            DataTable dataTable = GenericDataAccess.ExecuteSelectCommand(command);
            if (dataTable.Rows.Count == 1)
            {
                DataRow row = dataTable.Rows[0];
                this.fullname = row["Name"].ToString();
                this.facilityCode = row["FacCode"].ToString();
                //this.senderRegistered = true;

                int userTitle = Int32.Parse(row["TitleID"].ToString());
                if (userTitle == DATA_CLERK) this.userTitle = UserTitle.DATA_CLERK;
                if (userTitle == DRCHCO) this.userTitle = UserTitle.DRCHCO;
                if (userTitle == RRCHCO) this.userTitle = UserTitle.RRCHCO;
                if (userTitle == SI) this.userTitle = UserTitle.SI;
                if (userTitle == OTHERS) this.userTitle = UserTitle.OTHERS;
                return true;
            }
            else
            {
                //this.senderRegistered = false;
                return false;
            }
        }

        private void ValidateReportingText(string reportingText)
        {
            reportingText = reportingText.Trim();
            if (String.IsNullOrEmpty(reportingText))
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.FEW_REPORT_PARAMETERS;
                this.errorTextLabelID = FEW_REPORT_PARAMETERS_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, FEW_REPORT_PARAMETERS_LABEL);

                e.Status = ReportingError.GetReportingError(this.errorCode);
                //TODO: Fire event when the reporting text is empty
                return;
            }

            string[] parts = reportingText.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
            // It should contain at least this formart [RepID].[FacCode],[Period],[Year],[...,]
            int minimumRequiredParts = -1;
            if (type == ReportingType.SENDING)
            {
                minimumRequiredParts = 4;
                this.reportingLevel = ReportLevel.FACILITY;
            }
            if (type == ReportingType.REQUEST) minimumRequiredParts = 6;
            if (parts.Length >= minimumRequiredParts)
            {
                // For requesting there should be exactly six parameters separated by ,
                if (type == ReportingType.REQUEST)
                {
                    #region Request Reports
                    if (parts.Length == minimumRequiredParts)
                    {
                        string report = parts[0];
                        string partialFacilityCode = parts[1];
                        string startPeriod = parts[2];
                        string startYear = parts[3];
                        string endPeriod = parts[4];
                        string endYear = parts[5];

                        ValidateReportExistance(report);
                        if (this.hasError) return;

                        // Finding the actual partial facility code
                        this.reportingLevel = ReportLevel.FACILITY;
                        if (partialFacilityCode.EndsWith("000000"))
                        {
                            this.reportingLevel = ReportLevel.REGION;
                            partialFacilityCode = partialFacilityCode.Substring(0, 2);
                        }
                        else
                        {
                            if (partialFacilityCode.EndsWith("0000"))
                            {
                                this.reportingLevel = ReportLevel.DISTRICT;
                                partialFacilityCode = partialFacilityCode.Substring(0, 4);
                            }
                        }

                        ValidateFacilityCode(partialFacilityCode);
                        if (this.hasError) return;
                        this.partialFacilityCode = partialFacilityCode;

                        ValidateTimeFrame(startPeriod, startYear, endPeriod, endYear);
                        return;
                    }
                    else
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.MANY_REPORT_PARAMETERS;
                        this.errorTextLabelID = MANY_REPORT_PARAMETERS_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum, MANY_REPORT_PARAMETERS_LABEL);
                        return;
                    }
                    #endregion
                }

                string[] firstComponents = parts[0].Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);
                if (firstComponents.Length != 2)
                {
                    // parts[0] contains keyword eg. ANC instead of keyword with facility code
                    // The usual value would be something like ANC.04010100
                    // The facility code is now in parts[1] instead of being part of parts[0]
                    // parts[1] should contain the period
                    if (SMSFormat == SMSReportingFormat.FLEXIBLE || SMSFormat == SMSReportingFormat.HIGHLY_ADAPTIVE)
                    {
                        firstComponents = new string[] { parts[0], parts[1] };
                        string[] newParts = new string[parts.Length - 1];
                        newParts[0] = string.Format("{0}.{1}", parts[0], parts[1]);
                        for (int i = 1; i < newParts.Length; i++) newParts[i] = parts[i + 1];
                        parts = newParts;
                    }
                }

                if (firstComponents.Length == 2)
                {
                    #region Checking Report Preliminary Parameters
                    string report = firstComponents[0];
                    ValidateReportExistance(report);
                    if (this.hasError) return;

                    string facCode = firstComponents[1];
                    ValidateFacilityCode(facCode);
                    if (this.hasError) return;

                    ValidateExpectedReports();
                    if (this.hasError) return;

                    string period = parts[1];
                    if (period.Contains("."))
                    {
                        // Oh! This month text contains period. eg. 2.2013 or Jan.2013
                        // This needs to be replace and split apart to get two parts
                        // But all of this depends on the SMS format
                        if (SMSFormat == SMSReportingFormat.FLEXIBLE ||
                            SMSFormat == SMSReportingFormat.HIGHLY_ADAPTIVE)
                        {
                            string[] pp = period.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries);
                            string[] newParts = new string[parts.Length + pp.Length - 1 /* One element is already contained*/];
                            newParts[0] = parts[0];
                            for (int i = 0; i < pp.Length; i++) newParts[i + 1] = pp[i];
                            for (int i = 1 + pp.Length; i < newParts.Length; i++) newParts[i] = parts[i - pp.Length + 1];
                            
                            parts = newParts;
                            period = parts[1];
                        }
                    }
                    ValidatePeriod(period);
                    if (hasError) return;

                    string year = parts[2];
                    ValidateYear(year);
                    if (hasError) return;
                    
                    e.ReportMonth = this.period;
                    e.ReportYear = this.year;
                    #endregion

                    #region Checking Re-submission
                    string lastWord = parts[parts.Length - 1];
                    int dataCount = -1;
                    lastWord = lastWord.ToLower();
                    switch (lastWord)
                    {
                        case "re":
                        case "resubmit":
                        case "rekebisha":
                        case "marekebisho":
                        case "sahihisha":
                        case "sahihi":
                        case "rudia":
                        case "tumatena":
                        case "tumaupya":
                        case "badili":
                            dataCount = parts.Length - 1;
                            this.resubmission = true;
                            break;

                        default:
                            dataCount = parts.Length;
                            this.resubmission = false;
                            break;
                    }

                    this.data = new List<string>();
                    for (int i = 3; i < dataCount; i++)
                    {
                        string value = parts[i];
                        if (SMSFormat == SMSReportingFormat.FLEXIBLE 
                            || SMSFormat == SMSReportingFormat.HIGHLY_ADAPTIVE)
                        {
                            if (value.Contains("."))
                            {
                                string[] segments = value.Split(new string[] { "." },
                                    StringSplitOptions.RemoveEmptyEntries);
                                foreach (var s in segments) data.Add(s);
                            }
                            else data.Add(value);
                        }
                        else data.Add(value);
                    }

                    e.Resubmission = this.resubmission;
                    #endregion

                    #region Checking business Rules
                    ValidateReportBusinessRules();
                    if (hasError)
                    {
                        if (e.ReEvaluate)   // this is done only one time for now.
                        {
                            ValidateReportBusinessRules();
                            if (hasError) return;
                        }
                        else return;
                    }
                    #endregion
                }
                else
                {
                    this.hasError = true;
                    this.invalid = false;
                    this.errorCode = ReportProcessingError.INVALID_REPORT_INITIALIZATION;
                    this.errorTextLabelID = INVALID_REPORT_INITIALIZATION_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_REPORT_INITIALIZATION_LABEL);
                    return;
                }
            }
            else
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.FEW_REPORT_PARAMETERS;
                this.errorTextLabelID = FEW_REPORT_PARAMETERS_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, FEW_REPORT_PARAMETERS_LABEL);
                return;
            }
        }

        /// <summary>
        /// Checks to see whether the report version exists in the system.
        /// If it exists, the ID is stored in the internal variable reportID for later use.
        /// </summary>
        /// <param name="reportVersion">Report versio to check</param>
        /// <returns>True is exists otherwise false</returns>
        private void ValidateReportExistance(string reportVersion)
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT RepID, ReportName FROM Report WHERE RepVersion = @ReportVersion";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@ReportVersion";
            param.DbType = DbType.String;
            param.Value = reportVersion;
            command.Parameters.Add(param);

            DataTable dataTable = GenericDataAccess.ExecuteSelectCommand(command);
            if (dataTable.Rows.Count == 1)
            {
                DataRow row = dataTable.Rows[0];
                this.reportID = int.Parse(row["RepID"].ToString());
                this.reportKeyword = reportVersion;
                this.reportName = row["ReportName"].ToString();

                e.ReportId = this.reportID;
                e.ReportKeyword = this.reportKeyword;
            }
            else
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.REPORT_DOES_NOT_EXIST;
                this.errorTextLabelID = REPORT_DOES_NOT_EXIST_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, REPORT_DOES_NOT_EXIST_LABEL);

                e.Status = ReportingError.GetReportingError(this.errorCode);
                //TODO: Fire event when report does not exists
                return;
            }
        }

        private void ValidateFacilityCode(string facilityCode)
        {
            // This will replace any O with zero
            if (SMSFormat == SMSReportingFormat.FLEXIBLE || SMSFormat == SMSReportingFormat.HIGHLY_ADAPTIVE)
            {
                facilityCode = facilityCode.ToLower();
                facilityCode = facilityCode.Replace('o', '0');
            }

            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT TOP(1) FacCode, FacName FROM Facilities WHERE FacCode LIKE @FacCode + '%'";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@FacCode";
            param.DbType = DbType.String;
            param.Value = facilityCode;
            command.Parameters.Add(param);

            DataTable dataTable = GenericDataAccess.ExecuteSelectCommand(command);
            if (dataTable.Rows.Count == 1)
            {
                DataRow row = dataTable.Rows[0];
                string code = row["FacCode"].ToString();
                string name = row["FacName"].ToString();

                if (type == ReportingType.VALIDATION)
                {
                    this.facilityCode = code;
                    this.facilityName = name;
                    return;
                }

                // compare facility code with the one from user registration [where facilityCode was set]
                if (this.facilityCode == facilityCode)
                {
                    this.facilityName = name;
                    e.FacilityCode = this.facilityCode;
                }
                else
                {
                    // Facility level can access his/her facility only.
                    if (this.userTitle == UserTitle.DATA_CLERK)
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY;
                        this.errorTextLabelID = SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum,
                            SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL);

                        e.Status = ReportingError.GetReportingError(this.errorCode);
                        //TODO: Fire event when facility code is different from the registered code
                        return;
                    }

                    // District level can request regional data
                    if ((facilityCode.Length == 2) && (this.userTitle == UserTitle.DRCHCO))
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY;
                        this.errorTextLabelID = SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum,
                            SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL);

                        e.Status = ReportingError.GetReportingError(this.errorCode);
                        //TODO: Fire event when facility code is different from the registered code
                        return;
                    }

                    string partialName = Utilities.GetPartialFacilityName(facilityCode);
                    if (!String.IsNullOrEmpty(partialName))
                    {
                        this.facilityName = partialName;
                        return;
                    }
                    else
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY;
                        this.errorTextLabelID = SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum,
                            SENDER_NUMBER_IS_NOT_REGISTERED_FOR_SELECTED_FACILITY_LABEL);

                        e.Status = ReportingError.GetReportingError(this.errorCode);
                        //TODO: Fire event when facility code is different from the registered code
                        return;
                    }
                }
            }
            else
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.INVALID_FACILITY;
                this.errorTextLabelID = INVALID_FACILITY_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_FACILITY_LABEL);

                e.Status = ReportingError.GetReportingError(this.errorCode);
                //TODO: Fire event when facility code is invalid
                return;
            }
        }

        private void ValidatePeriod(string period)
        {
            string possibleMonthText = period;
            // This will replace any O with zero
            if (SMSFormat == SMSReportingFormat.FLEXIBLE || SMSFormat == SMSReportingFormat.HIGHLY_ADAPTIVE)
            {
                possibleMonthText = possibleMonthText.ToLower();
                possibleMonthText = possibleMonthText.Replace('o', '0');
            }

            int month;
            bool converted = int.TryParse(possibleMonthText, out month);
            if (converted)
            {
                if (month >= 1 && month <= 12)
                {
                    this.period = month;
                    return;
                }
                else
                {
                    this.hasError = true;
                    this.invalid = false;
                    this.errorCode = ReportProcessingError.INVALID_PERIOD;
                    this.errorTextLabelID = INVALID_PERIOD_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_PERIOD_LABEL);
                }
            }
            else
            {
                // If the text contain the text in english
                string[] months = 
                { 
                    "january", "february", "march", "april", 
                    "may", "june", "julay", "august", 
                    "september", "october", "november", "december"
                };

                period = period.ToLower();
                for (int i = 0; i < months.Length; i++)
                {
                    if (months[i].Contains(period))
                    {
                        month = i + 1;
                        this.period = month;
                        return;
                    }
                }

                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.INVALID_PERIOD;
                this.errorTextLabelID = INVALID_PERIOD_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_PERIOD_LABEL);
            }
        }

        /// <summary>
        /// Validates the report month
        /// </summary>
        /// <param name="period">Month expression</param>
        /// <param name="iPeriod">Reply - Month as an integer</param>
        /// <param name="errorText">Reply - Error text if occured</param>
        /// <returns>True if the month is valid otherwise false</returns>
        public static bool ValidatePeriod(string period, out int iPeriod, out string errorText)
        {
            bool valid = false;
            iPeriod = -1;
            errorText = valid.ToString();

            int month;
            bool converted = int.TryParse(period, out month);
            if (converted)
            {
                if (month >= 1 && month <= 12)
                {
                    iPeriod = month;
                    valid = true;
                    errorText = valid.ToString();
                }
                else
                {
                    errorText = Utilities.GetTranslationText(INVALID_PERIOD_LABEL);
                }
            }
            else
            {
                // If the text contain the text in english
                string[] months = 
                { 
                    "january", "february", "march", "april", 
                    "may", "june", "july", "august", 
                    "september", "october", "november", "december"
                };

                period = period.ToLower();
                for (int i = 0; i < months.Length; i++)
                {
                    if (months[i].Contains(period))
                    {
                        month = i + 1;
                        iPeriod = month;
                        valid = true;
                        break;
                    }
                }

                if (!valid)
                {
                    errorText = Utilities.GetTranslationText(INVALID_PERIOD_LABEL);
                }
            }
            return valid;
        }

        private void ValidateYear(string year)
        {
            int iYear = 0;
            int maxDelay = AppConfiguration.MaximumReportDelay;
            bool converted = int.TryParse(year, out iYear);

            if (converted)
            {
                if (iYear < BASELINE_YEAR) iYear = BASELINE_YEAR;
                if (iYear > UPPER_LIMIT_YEAR)
                {
                    this.hasError = true;
                    this.invalid = false;
                    this.errorCode = ReportProcessingError.REPORT_HAS_FUTURE_RECORDS;
                    this.errorTextLabelID = REPORT_HAS_FUTURE_RECORDS_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, REPORT_HAS_FUTURE_RECORDS_LABEL);
                    return;
                }

                DateTime twoYearsBack = DateTime.Now.AddYears(-maxDelay);
                DateTime currentTime = DateTime.Now;
                DateTime reportTime = DateTime.Parse(String.Format("{0}-{1}-1", iYear, this.period));

                if (reportTime <= currentTime)
                {
                    if (reportTime >= twoYearsBack)
                    {
                        if ((this.mode & ReportingMode.ALLOW_SAME_MONTH_REPORTING) != ReportingMode.ALLOW_SAME_MONTH_REPORTING)
                        {
                            int currentMonth = DateTime.Now.Month;
                            int currentYear = DateTime.Now.Year;
                            if ((currentMonth == reportTime.Month) && (currentYear == reportTime.Year))
                            {
                                this.hasError = true;
                                this.invalid = false;
                                this.errorCode = ReportProcessingError.CURRENT_MONTH_REPORTING_NOT_ALLOWED;
                                this.errorTextLabelID = CURRENT_MONTH_REPORTING_NOT_ALLOWED_LABEL;
                                this.errorText = Utilities.GetTranslationText(this.senderNum, CURRENT_MONTH_REPORTING_NOT_ALLOWED_LABEL);
                                return;
                            }
                        }
                        
                        this.year = iYear;
                        return;
                    }
                    else
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.REPORT_IS_VERY_OLD;
                        this.errorTextLabelID = REPORT_IS_VERY_OLD_LABEL;
                        string error = Utilities.GetTranslationText(this.senderNum, REPORT_IS_VERY_OLD_LABEL);
                        this.errorText = String.Format(error, AppConfiguration.MaximumReportDelay);
                        return;
                    }
                }
                else
                {
                    this.hasError = true;
                    this.invalid = false;
                    this.errorCode = ReportProcessingError.REPORT_HAS_FUTURE_RECORDS;
                    this.errorTextLabelID = REPORT_HAS_FUTURE_RECORDS_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, REPORT_HAS_FUTURE_RECORDS_LABEL);
                    return;
                }
            }
            else
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.INVALID_YEAR;
                this.errorTextLabelID = INVALID_YEAR_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_YEAR_LABEL);
                return;
            }
        }

        /// <summary>
        /// Validates the combination of month and year
        /// </summary>
        /// <param name="sYear">Year expression</param>
        /// <param name="period">Month as an integer</param>
        /// <param name="mode">Reporting Mode</param>
        /// <param name="year">Reply - Year as an integer</param>
        /// <param name="errorText">Reply - Error text if occured</param>
        /// <returns>True if the combination is valid otherwise false</returns>
        public static bool ValidateMonthAndYear(string sYear, int period, ReportingMode mode,
            out int year, out string errorText, out int errorCode)
        {
            bool valid = false;
            year = -1;
            errorText = valid.ToString();

            int iYear = 0;
            int maxDelay = AppConfiguration.MaximumReportDelay;
            bool converted = int.TryParse(sYear, out iYear);
            if (converted)
            {
                if (iYear < BASELINE_YEAR) iYear = BASELINE_YEAR;

                DateTime twoYearsBack = DateTime.Now.AddYears(-maxDelay);
                DateTime currentTime = DateTime.Now;
                DateTime reportTime;
                converted = DateTime.TryParse(string.Format("{0}-{1}-1", iYear, period), out reportTime);
                if (!converted)
                {
                    errorCode = ReportingError.INVALID_YEAR_LABEL;
                    errorText = Utilities.GetTranslationText(ReportingError.INVALID_YEAR_LABEL);
                    valid = false;
                    return valid;
                }

                if (reportTime <= currentTime)
                {
                    if (reportTime >= twoYearsBack)
                    {
                        if ((mode & ReportingMode.ALLOW_SAME_MONTH_REPORTING) != ReportingMode.ALLOW_SAME_MONTH_REPORTING)
                        {
                            int currentMonth = DateTime.Now.Month;
                            if ((reportTime.Year == currentTime.Year) && (currentMonth == reportTime.Month))
                            {
                                //this.errorCode = ReportProcessingError.CURRENT_MONTH_REPORTING_NOT_ALLOWED;
                                //this.errorTextLabelID = CURRENT_MONTH_REPORTING_NOT_ALLOWED_LABEL;
                                errorCode = ReportingError.CURRENT_MONTH_REPORTING_NOT_ALLOWED_LABEL;
                                errorText = Utilities.GetTranslationText(ReportingError.CURRENT_MONTH_REPORTING_NOT_ALLOWED_LABEL);
                                valid = false;
                                return valid;
                            }
                        }
                        year = iYear;
                        valid = true;
                        errorCode = ReportingError.NO_ERROR_LABEL;
                        return valid;
                    }
                    else
                    {
                        //this.errorCode = ReportProcessingError.REPORT_IS_VERY_OLD;
                        //this.errorTextLabelID = REPORT_IS_VERY_OLD_LABEL;
                        errorCode = ReportingError.REPORT_IS_VERY_OLD_LABEL;
                        string error = Utilities.GetTranslationText(ReportingError.REPORT_IS_VERY_OLD_LABEL);
                        errorText = String.Format(error, AppConfiguration.MaximumReportDelay);
                        valid = false;
                        return valid;
                    }
                }
                else
                {
                    //this.errorCode = ReportProcessingError.REPORT_HAS_FUTURE_RECORDS;
                    //this.errorTextLabelID = REPORT_HAS_FUTURE_RECORDS_LABEL;
                    errorCode = ReportingError.REPORT_HAS_FUTURE_RECORDS_LABEL;
                    errorText = Utilities.GetTranslationText(ReportingError.REPORT_HAS_FUTURE_RECORDS_LABEL);
                    valid = false;
                    return valid;
                }
            }
            else
            {
                errorCode = ReportingError.INVALID_YEAR_LABEL;
                errorText = Utilities.GetTranslationText(ReportingError.INVALID_YEAR_LABEL);
                valid = false;
                return valid;
            }
            return valid;
        }

        private void ValidateExpectedReports()
        {
            if ((this.mode & ReportingMode.IGNORE_EXPECTED_REPORTS) == ReportingMode.IGNORE_EXPECTED_REPORTS) return;

            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT COUNT([ReportID]) AS count FROM ExpectedReports 
                WHERE FacCode=@FacCode AND ReportID=@ReportID AND DirectEntry = 1";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@FacCode";
            param.DbType = DbType.String;
            param.Value = this.facilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            string output = GenericDataAccess.ExecuteScalar(command);
            int count = int.Parse(output);
            if (count != 1)
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.SUCH_REPORT_IS_NOT_EXPECTED_FROM_FACILITY;
                this.errorTextLabelID = SUCH_REPORT_IS_NOT_EXPECTED_FROM_FACILITY_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, SUCH_REPORT_IS_NOT_EXPECTED_FROM_FACILITY_LABEL);

                e.Status = ReportingError.GetReportingError(this.errorCode);
                //TODO: Fire event when report is not expected
                return;
            }
        }

        private void ValidateTimeFrame(string startPeriod, string startYear, string endPeriod, string endYear)
        {
            ValidatePeriod(startPeriod);
            if (this.hasError) return;
            this.startPeriod = this.period;

            ValidateYear(startYear);
            if (this.hasError) return;
            this.startYear = this.year;

            ValidatePeriod(endPeriod);
            if (this.hasError) return;
            this.endPeriod = this.period;

            ValidateYear(endYear);
            if (this.hasError) return;
            this.endYear = this.year;

            string startTimeText = String.Format("{0}-{1}-1", this.startYear, this.startPeriod);
            string endTimeText = String.Format("{0}-{1}-1", this.endYear, endPeriod);
            DateTime startTime = DateTime.Parse(startTimeText);
            DateTime endTime = DateTime.Parse(endTimeText);
            if (endTime < startTime)
            {
                this.hasError = true;
                this.invalid = false;
                this.errorCode = ReportProcessingError.INVALID_TIMEFRAME;
                this.errorTextLabelID = INVALID_TIMEFRAME_LABEL;
                this.errorText = Utilities.GetTranslationText(this.senderNum, INVALID_TIMEFRAME_LABEL);
                return;
            }
        }

        private void ValidateReportBusinessRules()
        {
            // Up to this point there should be no errors
            // so we're going to ignore any previous generated error
            this.hasError = false;
            this.errorCode = ReportProcessingError.NO_ERROR;
            this.errorTextLabelID = NO_ERROR_LABEL;
            this.errorText = Utilities.GetTranslationText(this.senderNum, NO_ERROR_LABEL);

            #region Checking Report Parameter Count
            // Saving all report parameter for DB insert
            if (e.ReEvaluate && this.reportData.Count > 0)
            {
                if (e.ReportId.HasValue) this.reportID = e.ReportId.Value;
                this.reportData = e.ResolvedDataElements;
            }
            else
            {
                this.reportData.Clear();
                this.reportData.Add(this.facilityCode);
                this.reportData.Add(this.period.ToString());
                this.reportData.Add(this.year.ToString());
                foreach (string d in this.data) this.reportData.Add(d);

                e.ResolvedDataElements = this.reportData;
            }

            int requiredParameterCount = GetReportDataParameterCount();
            if (requiredParameterCount != reportData.Count)
            {
                if (requiredParameterCount > reportData.Count)
                {
                    this.errorCode = ReportProcessingError.FEW_REPORT_PARAMETERS;
                    this.errorTextLabelID = FEW_REPORT_PARAMETERS_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, FEW_REPORT_PARAMETERS_LABEL);

                    e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
                    if (ReportBussinessRulesFailed != null) ReportBussinessRulesFailed(this, e);
                }
                else
                {
                    this.errorCode = ReportProcessingError.MANY_REPORT_PARAMETERS;
                    this.errorTextLabelID = MANY_REPORT_PARAMETERS_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, MANY_REPORT_PARAMETERS_LABEL);

                    e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
                    if (ReportBussinessRulesFailed != null) ReportBussinessRulesFailed(this, e);
                }
                this.hasError = true;
                this.invalid = false;
                return;
            }
            #endregion

            //E.g. ANC Jan 2013: Taarifa yako imepokolewa...
            this.errorText = String.Format("{0} {1} {2}: {3}", this.reportKeyword, Utilities.GetMonthText(this.period, true),
                this.year, this.errorText);

            DataTable reportDataLocation = GetReportDataLocations();
            // Validating data types
            #region Validating data types
            for (int i = 0; i < this.reportData.Count; i++)
            {
                int iValue = 0;
                decimal dValue = 0.0M;
                string msg = String.Empty;
                string shortCode = String.Empty;

                DataRow row = reportDataLocation.Rows[i];
                string dataType = row["DataType"].ToString();
                switch (dataType)
                {
                    case TEXT:
                        break;

                    case INTEGER:
                        try
                        {
                            iValue = Int32.Parse(this.reportData[i]);
                        }
                        catch
                        {
                            this.hasError = true;
                            this.invalid = false;
                            this.errorCode = ReportProcessingError.NON_INTEGER_VALUE;
                            this.errorTextLabelID = NON_INTEGER_VALUE_LABEL;
                            msg = Utilities.GetTranslationText(this.senderNum, NON_INTEGER_VALUE_LABEL);
                            shortCode = row["ShortCode"].ToString();
                            this.errorText = String.Format(msg, shortCode, this.reportData[i]);

                            //E.g. ANC Jan 2013: Kosa kwenye taarifa...
                            this.errorText = String.Format("{0} {1} {2}: {3}", this.reportKeyword, Utilities.GetMonthText(this.period, true),
                                this.year, this.errorText);

                            e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
                            if (ReportBussinessRulesFailed != null) ReportBussinessRulesFailed(this, e);
                            return;
                        }
                        break;

                    case DECIMAL:
                        try
                        {
                            dValue = Decimal.Parse(this.reportData[i]);
                        }
                        catch
                        {
                            this.hasError = true;
                            this.invalid = false;
                            this.errorCode = ReportProcessingError.NON_DECIMAL_VALUE;
                            this.errorTextLabelID = NON_DECIMAL_VALUE_LABEL;
                            msg = Utilities.GetTranslationText(this.senderNum, NON_DECIMAL_VALUE_LABEL);
                            shortCode = row["ShortCode"].ToString();
                            this.errorText = String.Format(msg, shortCode, this.reportData[i]);
                            //E.g. ANC Jan 2013: Kosa kwenye taarifa...
                            this.errorText = String.Format("{0} {1} {2}: {3}", this.reportKeyword, Utilities.GetMonthText(this.period, true),
                                this.year, this.errorText);

                            e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
                            if (ReportBussinessRulesFailed != null) ReportBussinessRulesFailed(this, e);
                            return;
                        }
                        break;
                }
            }
            #endregion

            //int offset = 4; //this is because position 1,2,3 are for code, period and year. Don't forget zero-based list/array.
            DataTable dataTable = GetReportBusinessRules();
            for (int i = 0; i < dataTable.Rows.Count; i++)
            {
                DataRow row = dataTable.Rows[i];
                int measurePosNo = int.Parse(row["MeasurePosNo"].ToString());
                string comparedToOrderPos = row["ComparedToOrderPos"].ToString();
                bool multicomparison = bool.Parse(row["Multicomparison"].ToString());
                string comparisonSign = row["ComparisonSign"].ToString();

                decimal value1 = 0.0M;
                decimal value2 = 0.0M;

                if (multicomparison)
                {
                    #region Dealing with Multicomparison
                    ArithmeticOperation operation = ArithmeticOperation.ADD;
                    //value1 = data[measurePosNo - offset];
                    value1 = Decimal.Parse(this.reportData[measurePosNo - 1]);
                    StringBuilder sBuilder = new StringBuilder();
                    sBuilder.Append("(");
                    string[] parts = comparedToOrderPos.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string part in parts)
                    {
                        try
                        {
                            int position = int.Parse(part);
                            //int value = data[position - offset];
                            decimal value = Decimal.Parse(this.reportData[position - 1]);
                            string shortCode = reportDataLocation.Rows[position - 1]["ShortCode"].ToString();
                            sBuilder.Append(shortCode);
                            switch (operation)
                            {
                                case ArithmeticOperation.ADD:
                                    value2 += value;
                                    break;

                                case ArithmeticOperation.SUBTRACT:
                                    value2 -= value;
                                    break;

                                case ArithmeticOperation.MULTIPLY:
                                    value2 *= value;
                                    break;

                                case ArithmeticOperation.DIVIDE:
                                    value2 /= value;
                                    break;
                            }
                        }
                        catch
                        {
                            switch (part)
                            {
                                case "+":
                                    operation = ArithmeticOperation.ADD;
                                    sBuilder.Append("+");
                                    break;

                                case "-":
                                    operation = ArithmeticOperation.SUBTRACT;
                                    sBuilder.Append("-");
                                    break;

                                case "*":
                                    operation = ArithmeticOperation.MULTIPLY;
                                    sBuilder.Append("*");
                                    break;

                                case "/":
                                    operation = ArithmeticOperation.DIVIDE;
                                    sBuilder.Append("/");
                                    break;
                            }
                        }
                    }
                    sBuilder.Append(")");
                    bool okToContinue = Utilities.Compare(value1, comparisonSign, value2);
                    if (!okToContinue)
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.BUSINESS_RULES_FAILURE;
                        this.errorTextLabelID = BUSINESS_RULES_FAILURE_LABEL;

                        string sValue1 = reportDataLocation.Rows[measurePosNo - 1]["ShortCode"].ToString();
                        string sValue2 = sBuilder.ToString();

                        string msg = Utilities.GetTranslationText(this.senderNum, COMPARISON_LABEL);
                        string signText = GetSignText(comparisonSign);
                        this.errorText = String.Format(msg, sValue1, signText, sValue2);
                        //E.g. ANC Jan 2013: Kosa kwenye taarifa...
                        this.errorText = String.Format("{0} {1} {2}: {3}", this.reportKeyword, Utilities.GetMonthText(this.period, true),
                            this.year, this.errorText);

                        e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
                        if (ReportBussinessRulesFailed != null) ReportBussinessRulesFailed(this, e);

                        return;
                    }
                    #endregion
                }
                else
                {
                    #region Dealing with Simple Comparison
                    bool value2IsScalar = false;
                    int comparePosNo = 0;
                    //value1 = data[measurePosNo - offset];
                    value1 = Decimal.Parse(this.reportData[measurePosNo - 1]);
                    if (comparedToOrderPos.Contains("["))
                    {
                        value2IsScalar = true;
                        string value = comparedToOrderPos.Substring(1, comparedToOrderPos.Length - 2);
                        //value2 = Int32.Parse(value);
                        value2 = Decimal.Parse(value);
                    }
                    else
                    {
                        comparePosNo = int.Parse(comparedToOrderPos);
                        //value2 = data[comparePosNo - offset];    
                        value2 = Decimal.Parse(this.reportData[comparePosNo - 1]);
                    }
                    bool okToContinue = Utilities.Compare(value1, comparisonSign, value2);
                    if (!okToContinue)
                    {
                        this.hasError = true;
                        this.invalid = false;
                        this.errorCode = ReportProcessingError.BUSINESS_RULES_FAILURE;
                        this.errorTextLabelID = BUSINESS_RULES_FAILURE_LABEL;

                        string sValue1 = reportDataLocation.Rows[measurePosNo - 1]["ShortCode"].ToString();
                        string sValue2 = String.Empty;
                        if (value2IsScalar) sValue2 = value2.ToString();
                        else sValue2 = reportDataLocation.Rows[comparePosNo - 1]["ShortCode"].ToString();

                        string msg = Utilities.GetTranslationText(this.senderNum, COMPARISON_LABEL);
                        string signText = GetSignText(comparisonSign);
                        this.errorText = String.Format(msg, sValue1, signText, sValue2);
                        //E.g. ANC Jan 2013: Kosa kwenye taarifa...
                        this.errorText = String.Format("{0} {1} {2}: {3}", this.reportKeyword, Utilities.GetMonthText(this.period, true),
                            this.year, this.errorText);

                        e.Status = ReportingError.GetReportingError(this.errorCode, this.senderNum);
                        if (ReportBussinessRulesFailed != null) ReportBussinessRulesFailed(this, e);
                        return;
                    }
                    #endregion
                }
            }
            return;
        }

        private DataTable GetReportBusinessRules()
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT ReportBusinessRules.BRNo, ReportBusinessRules.RepID, 
                ReportBusinessRules.MeasurePosNo, ReportBusinessRules.RuleDescription, ReportBusinessRules.Action, 
                ReportBusinessRules.ComparedToOrderPos, ReportBusinessRules.ComparisonType, 
                ReportBusinessRules.Multicomparison, ComparisonType.ComparisonSign FROM ReportBusinessRules 
                INNER JOIN ComparisonType ON ReportBusinessRules.ComparisonType = ComparisonType.ComparisonType
                WHERE (ReportBusinessRules.RepID = @RepID)";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@RepID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            DataTable dataTable = GenericDataAccess.ExecuteSelectCommand(command);
            return dataTable;
        }

        private DataTable GetReportDataLocations()
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT MeasureNo, RepID, DataDescription, DataPosition, DataType, ShortCode 
                FROM ReportDataLocations WHERE RepID=@RepID ORDER BY DataPosition ASC";
            DbParameter param = command.CreateParameter();
            param.ParameterName = "@RepID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            DataTable output = GenericDataAccess.ExecuteSelectCommand(command);
            return output;
        }

        private int GetReportDataParameterCount()
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT COUNT(DataPosition) AS [Count] FROM ReportDataLocations WHERE (RepID = @RepID)";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@RepID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            string output = GenericDataAccess.ExecuteScalar(command);
            int count = int.Parse(output);
            return count;
        }

        private bool SubmitReport()
        {
            if (SavingReport != null) SavingReport(this, e);
            if (e.CancelOperation) return false;

            int receivedSMSNo = -1;
            bool saved = false;
            bool submitted = IsReportSubmitted(out receivedSMSNo);
            if (submitted)
            {
                if (this.resubmission)
                {
                    DeleteReport(receivedSMSNo);
                    InsertReport();
                    if (this.hasError) saved = false;
                    else saved = true;
                }
                else
                {
                    this.hasError = true;
                    this.invalid = false;
                    this.errorCode = ReportProcessingError.REPORT_ALREADY_SUBMITTED;
                    this.errorTextLabelID = REPORT_ALREADY_SUBMITTED_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, REPORT_ALREADY_SUBMITTED_LABEL);
                    saved = false;
                }
            }
            else
            {
                if (this.resubmission)
                {
                    this.hasError = true;
                    this.invalid = false;
                    this.errorCode = ReportProcessingError.RESUBMIT_NON_EXISTING_REPORT;
                    this.errorTextLabelID = RESUBMIT_NON_EXISTING_REPORT_LABEL;
                    this.errorText = Utilities.GetTranslationText(this.senderNum, RESUBMIT_NON_EXISTING_REPORT_LABEL);
                    saved = false;
                }
                else
                {
                    InsertReport();
                    if (this.hasError) saved = false;
                    else saved = true;
                }
            }

            if (saved && AppConfiguration.EnableAutomaticDataMerging)
            {
                // Determine if there is a need for merging together with its mergeId
                DbCommand command = GenericDataAccess.CreateCommand();
                command.CommandType = CommandType.Text;
                command.CommandText = @"SELECT MergingReports.MergeId, MergingReports.DestinationReportId, 
                    MergingReports.SourceReportId FROM MergingReports INNER JOIN Report ON 
                    MergingReports.DestinationReportId = Report.RepID WHERE (Report.UsedAsView = 1) 
                    AND (MergingReports.DestinationReportId <> MergingReports.SourceReportId) 
                    AND (MergingReports.SourceReportId = @RepID)";

                // This query does not focus on reports used as view only, it aims to capture all
                // reports with auto-merge
//                command.CommandText = @"SELECT MergingReports.MergeId, MergingReports.DestinationReportId, 
//                    MergingReports.SourceReportId FROM MergingReports INNER JOIN Report ON 
//                    MergingReports.DestinationReportId = Report.RepID 
//                    WHERE (MergingReports.DestinationReportId <> MergingReports.SourceReportId) 
//                    AND (MergingReports.SourceReportId = @RepID)";

                DbParameter param = command.CreateParameter();
                param.ParameterName = "@RepID";
                param.DbType = DbType.Int32;
                param.Value = this.reportID;
                command.Parameters.Add(param);

                DataTable output = GenericDataAccess.ExecuteSelectCommand(command);
                // TODO: Allow automerge to more than one destination report
                //if (output.Rows.Count == 1)
                foreach (DataRow row in output.Rows)
                {
                    //DataRow row = output.Rows[0];
                    int mergeId = Int32.Parse(row["MergeId"].ToString());
                    bool merged = MergeReports(mergeId, AppConfiguration.OverwriteInAutoMerge);
                    if (!merged)
                    {
                        string errorLabel = string.Format("Data Merging and Business Rules Inconsistency. " +
                            "Reporting Text:{0}", reportingText);
                        Exception ex = new Exception(errorLabel);
                        Utilities.LogError(ex, null);
                    }
                }
            }
            return saved;
        }

        private bool IsReportSubmitted(out int receivedSMSNo)
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT ReceivedSMSNo FROM ReceivedSMS WHERE FacCode=@FacCode 
                AND Year=@Year AND Period=@Period AND RepID=@RepID";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@FacCode";
            param.DbType = DbType.String;
            param.Value = this.facilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@Year";
            param.DbType = DbType.Int32;
            param.Value = this.year;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@Period";
            param.DbType = DbType.Int32;
            param.Value = this.period;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@RepID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            string output = GenericDataAccess.ExecuteScalar(command);
            try
            {
                int id = int.Parse(output);
                receivedSMSNo = id;
                return true;
            }
            catch
            {
                receivedSMSNo = -1;
                return false;
            }
        }

        private void DeleteReport(int receivedSMSNo)
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"DELETE FROM ReportData WHERE ReceivedSMSNo = @ReceivedSMSNo";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@ReceivedSMSNo";
            param.DbType = DbType.Int32;
            param.Value = receivedSMSNo;
            command.Parameters.Add(param);

            GenericDataAccess.ExecuteNonQuery(command, false);

            command.CommandText = @"DELETE FROM ReceivedSMS WHERE ReceivedSMSNo = @ReceivedSMSNo";
            GenericDataAccess.ExecuteNonQuery(command, true);
        }

        private void InsertReport()
        {
            string reportId = Utilities.GetSetting(SETTING_MTUHA_MC_REPORT);
            int iReportId;
            bool converted = int.TryParse(reportId, out iReportId);
            if (converted)
            {
                // We are looking for MTUHA MC report
                // the report is quarterly based.
                if (this.reportID == iReportId)
                {
                    // Accepted months are 3, 6, 9 and 12
                    if ((this.period % Configurations.SystemSetting.MTUHA_MC_REPORT_INTERVAL_MONTHS) != 0)
                    {
                        this.hasError = true;
                        this.errorCode = ReportProcessingError.MTUHA_REPORT_MC_IS_QUARTERLY_REPORTED;
                        this.errorTextLabelID = ReportingError.MTUHA_REPORT_MC_IS_QUARTERLY_REPORTED_LABEL;
                        this.errorText = Utilities.GetTranslationText(this.senderNum, ReportingError.MTUHA_REPORT_MC_IS_QUARTERLY_REPORTED_LABEL);
                        return;
                    }
                }
            }

            DbCommand command = GenericDataAccess.CreateCommand();
            #region Insert report into ReceivedSMS table
            command.CommandType = CommandType.Text;
            command.CommandText = @"INSERT INTO ReceivedSMS(SenderNum, TxtDetails, DateReceived, Processed,
                FacCode, Year, Period, RepID, ReportDate) VALUES (@SenderNum, @TxtDetails, GETDATE(), 'FALSE', 
                @FacCode, @Year, @Period, @RepID, @ReportDate)";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@SenderNum";
            param.DbType = DbType.String;
            param.Value = this.senderNum;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@TxtDetails";
            param.DbType = DbType.String;
            param.Value = this.reportingText;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@FacCode";
            param.DbType = DbType.String;
            param.Value = this.facilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@Year";
            param.DbType = DbType.Int32;
            param.Value = this.year;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@Period";
            param.DbType = DbType.Int32;
            param.Value = this.period;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@RepID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportDate";
            param.DbType = DbType.DateTime;
            param.Value = DateTime.Parse(String.Format("{0}-{1}-1", this.year, this.period));
            command.Parameters.Add(param);

            GenericDataAccess.ExecuteNonQuery(command, false);

            command.CommandText = @"SELECT @@IDENTITY AS ID";
            string output = GenericDataAccess.ExecuteScalar(command, false);
            int receivedSMSNo = int.Parse(output);

            // Here is the new fix to allow comments to be recorded
            // We don't want to cause any error by introducing this fix            
            try
            {
                using (var db = new DataModels.Models.Context.IQSMS_TestDBContext())
                {
                    var reportInfo = (from i in db.ReceivedSMS
                                      where i.ReceivedSMSNo == receivedSMSNo
                                      select i).FirstOrDefault();
                    if (reportInfo != null)
                    {
                        reportInfo.Comments = this.reportComments;
                        db.SaveChanges();
                    }
                }
            }
            catch { }
            #endregion

            #region Insert report into ReportData table
            command.CommandText = @"INSERT INTO ReportData (ReceivedSMSNo, RepID, DataPosition, Data) 
                VALUES (@ReceivedSMSNo, @RepID, @DataPosition, @Data)";
            //for (int i = 0; i < this.reportData.Count; i++)
            for (int i = 0; i < this.e.ResolvedDataElements.Count; i++)
            {
                command.Parameters.Clear();
                param = command.CreateParameter();
                param.ParameterName = "@ReceivedSMSNo";
                param.DbType = DbType.Int32;
                param.Value = receivedSMSNo;
                command.Parameters.Add(param);

                param = command.CreateParameter();
                param.ParameterName = "@RepID";
                param.DbType = DbType.Int32;
                param.Value = this.reportID;
                command.Parameters.Add(param);

                param = command.CreateParameter();
                param.ParameterName = "@DataPosition";
                param.DbType = DbType.Int32;
                param.Value = i + 1;
                command.Parameters.Add(param);

                param = command.CreateParameter();
                param.ParameterName = "@Data";
                param.DbType = DbType.String;
                //param.Value = this.reportData[i];
                param.Value = this.e.ResolvedDataElements[i];
                command.Parameters.Add(param);

                GenericDataAccess.ExecuteNonQuery(command, false);
            }
            #endregion

            #region In case this was stock report only received in classical format
            // Here I mean it is received or saved in this format
            // TK.12345678,5,2014,4,8,2
            // Instead of usual 5,2014,dt4,un8,dbs2
            if (this.reportID == AppConfiguration.StockReportID)
            {
                if (AppConfiguration.EnableStockInformation)
                {
                    int determine = int.Parse(this.reportData[3]);
                    int unigold = int.Parse(this.reportData[4]);
                    int dbs = int.Parse(this.reportData[5]);
                    SaveTestKitDataIntoItsTable(this.facilityCode, this.period, this.year,
                        determine, unigold, dbs);
                }
            }

            #endregion

            #region Set Report as processed
            command.CommandText = @"UPDATE ReceivedSMS SET Processed=@Processed WHERE ReceivedSMSNo=@ReceivedSMSNo";
            command.Parameters.Clear();

            param = command.CreateParameter();
            param.ParameterName = "@Processed";
            param.DbType = DbType.Boolean;
            param.Value = true;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReceivedSMSNo";
            param.DbType = DbType.Int32;
            param.Value = receivedSMSNo;
            command.Parameters.Add(param);

            GenericDataAccess.ExecuteNonQuery(command, true);
            #endregion
        }

        private DataTable GetReportData()
        {
            DbCommand command = GenericDataAccess.CreateCommand();
            command.CommandType = CommandType.Text;
            command.CommandText = @"SELECT ReportData.DataPosition, ISNULL(SUM(CAST(ReportData.Data AS INT)), 0) 
                AS ReportData, ReportDataLocations.ShortCode FROM ReportData INNER JOIN ReceivedSMS ON 
                ReportData.ReceivedSMSNo = ReceivedSMS.ReceivedSMSNo INNER JOIN ReportDataLocations ON 
                ReportData.RepID = ReportDataLocations.RepID AND ReportData.DataPosition = ReportDataLocations.DataPosition
                WHERE (ReceivedSMS.Year BETWEEN @StartYear AND @EndYear) AND 
                (ReceivedSMS.Period BETWEEN @StartPeriod AND @EndPeriod) AND (ReportData.RepID = @ReportID) 
                AND (ReceivedSMS.FacCode LIKE @FacilityCode + '%') AND (ReportData.DataPosition > 3)
                GROUP BY ReportData.DataPosition, ReportDataLocations.ShortCode ORDER BY ReportData.DataPosition";

            DbParameter param = command.CreateParameter();
            param.ParameterName = "@StartYear";
            param.DbType = DbType.Int32;
            param.Value = this.startYear;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@EndYear";
            param.DbType = DbType.Int32;
            param.Value = this.endYear;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@StartPeriod";
            param.DbType = DbType.Int32;
            param.Value = this.startPeriod;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@EndPeriod";
            param.DbType = DbType.Int32;
            param.Value = this.endPeriod;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@FacilityCode";
            param.DbType = DbType.String;
            param.Value = this.partialFacilityCode;
            command.Parameters.Add(param);

            param = command.CreateParameter();
            param.ParameterName = "@ReportID";
            param.DbType = DbType.Int32;
            param.Value = this.reportID;
            command.Parameters.Add(param);

            DataTable dataTable = GenericDataAccess.ExecuteSelectCommand(command);
            return dataTable;
        }

        private bool IsValidOperation()
        {
            return true;
        }

        private string GetSignText(string sign)
        {
            string text = String.Empty;
            int labelID = -1;
            switch (sign)
            {
                case "=":
                    labelID = EQUALS_LABEL;
                    break;

                case "!=":
                    labelID = NOT_EQUALS_LABEL;
                    break;

                case ">":
                    labelID = GREATER_THAN_LABEL;
                    break;

                case ">=":
                    labelID = GREATER_THAN_OR_EQUALS_LABEL;
                    break;

                case "<":
                    labelID = LESS_THAN_LABEL;
                    break;

                case "<=":
                    labelID = LESS_THAN_OR_EQUALS_LABEL;
                    break;
            }
            text = Utilities.GetTranslationText(this.senderNum, labelID);
            return text;
        }

        /// <summary>
        /// Merges the reports based on particular definition of merging mergeId
        /// </summary>
        /// <param name="mergeId">Unique identifier of merging definitions and involved reports</param>
        /// <param name="overwrite">Whether the destination report should be overwritten or not</param>
        /// <returns>True if the process was successfully</returns>
        private bool MergeReports(int mergeId, bool overwrite)
        {
            bool merged = false;
            try
            {
                var status = Merging.MergeFacilityReports(mergeId, overwrite, this.facilityCode, 
                    this.year, this.period, this.year, this.period, this.senderNum);
                merged = status.Merged;
            }
            catch (Exception ex)
            {
                merged = false;
                Utilities.LogError(ex, null);
            }
            return merged;
        }

        #endregion
    }
}
